#include <commctrl.h>
#include <stdint.h>
#include <windows.h>

#define CALROW(row) (gf.rh + gf.rs) * row + gf.rs
#define CALCOL(col) (gf.cw + gf.cs) * col + gf.cs
#define CALW(colspan) colspan*(gf.cw + gf.cs) - gf.cs
#define DPI(n) MulDiv(n, dpi, 96)

#define GRID_MAIN_STYLE \
  WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_BORDER
#define GRID_DPIAWARE

typedef struct tGridArgs {
  int rh;
  int cw;
  int rs;
  int cs;
} GridArgs;

HWND hwnd;
GridArgs gf;
int rowarr[50] = {0};
int dpi;

void GridInit(int rowH, int colW, int rowS, int colS) {
#ifdef GRID_DPIAWARE
  HDC hDC = GetDC(NULL);
  dpi = GetDeviceCaps(hDC, LOGPIXELSX);
  gf = (GridArgs){DPI(rowH), DPI(colW), DPI(rowS), DPI(colS)};
#else
  gf = (GridArgs){rowH, colW, rowS, colS};
#endif
}

void GridAlert(LPCWSTR cont) { MessageBoxW(NULL, cont, L"通知", MB_OK); }

void GridMainWindow(HINSTANCE hInst, LPCWSTR title, WNDPROC WndProc, int row,
                    int col) {
  WNDCLASSW wc = {
      .lpszClassName = title,
      .hInstance = hInst,
      .hbrBackground = GetSysColorBrush(COLOR_3DFACE),
      .lpfnWndProc = WndProc,
      .hCursor = LoadCursor(0, IDC_ARROW),
      .hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(1)),
  };
  RegisterClassW(&wc);
  RECT r = {0, 0, CALCOL(col), CALROW(row)};
  AdjustWindowRect(&r, GRID_MAIN_STYLE, FALSE);

  int win_w = r.right - r.left;
  int win_h = r.bottom - r.top;
  int screen_w = GetSystemMetrics(SM_CXSCREEN);
  int screen_h = GetSystemMetrics(SM_CYSCREEN);

  CreateWindowW(wc.lpszClassName, title, WS_VISIBLE | GRID_MAIN_STYLE,
                (screen_w - win_w) / 2, (screen_h - win_h) / 2, win_w, win_h,
                NULL, NULL, hInst, NULL);
}

void GridSetHwnd(HWND wn) { hwnd = wn; }

void GridSetSysfont() {
  size_t sz = sizeof(NONCLIENTMETRICSW);
  NONCLIENTMETRICSW s = {.cbSize = sz};
  SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sz, &s, 0);
  HFONT hf = CreateFontIndirectW(&s.lfMessageFont);
  BOOL CALLBACK SetFont(HWND child, LPARAM font) {
    SendMessageW(child, WM_SETFONT, font, TRUE);
    return TRUE;
  }
  EnumChildWindows(hwnd, (WNDENUMPROC)SetFont, (LPARAM)hf);
}

/* 为什么我感觉这个调不调都不影响。。算了留着吧 */
void GridInitComctl() {
  INITCOMMONCONTROLSEX icex;
  icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  icex.dwICC = ICC_STANDARD_CLASSES;
  InitCommonControlsEx(&icex);
}

void UpdateRowArr(int row, int colspan, int rowspan) {
  for (int i = 0; i < rowspan; i++) {
    rowarr[row + i] += colspan;
  }
}

HWND GridLabel(int row, int colspan, int rowspan, LPCWSTR text) {
  HWND out = CreateWindowW(L"Static", text, WS_CHILD | WS_VISIBLE | SS_LEFT,
                           CALCOL(rowarr[row]), CALROW(row) + DPI(2),
                           CALW(colspan), gf.rh - DPI(2), hwnd, 0, NULL, NULL);
  UpdateRowArr(row, colspan, rowspan);
  return out;
}

HWND GridInput(int row, int colspan, int rowspan, uintptr_t menu, DWORD style) {
  HWND out = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
                             WS_CHILD | WS_VISIBLE | style, CALCOL(rowarr[row]),
                             CALROW(row), CALW(colspan), gf.rh, hwnd,
                             (HMENU)menu, NULL, NULL);
  UpdateRowArr(row, colspan, rowspan);
  return out;
}

void GridButton(int row, int colspan, int rowspan, uintptr_t menu,
                LPCWSTR text) {
  CreateWindowW(L"button", text, WS_CHILD | WS_VISIBLE, CALCOL(rowarr[row]),
                CALROW(row) - DPI(1), CALW(colspan), gf.rh + DPI(2), hwnd,
                (HMENU)menu, NULL, NULL);
  UpdateRowArr(row, colspan, rowspan);
}

HWND GridProgress(int row, int colspan, int rowspan, uintptr_t menu) {
  HWND out = CreateWindowExW(0, PROGRESS_CLASSW, NULL,
                             WS_CHILD | WS_VISIBLE | PBS_MARQUEE,
                             CALCOL(rowarr[row]), CALROW(row), CALW(colspan),
                             gf.rh, hwnd, (HMENU)menu, NULL, NULL);
  UpdateRowArr(row, colspan, rowspan);
  return out;
}

void GridSetTopmost() {
  SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}